﻿using blackhouse.WebNemo.Business;
using blackhouse.WebNemo.Business.Extensionable;
using blackhouse.WebNemo.Business.Groups;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace blackhouse.WebNemo.Web.Controls {
    public class BlockReferencesEditRecordValue : EditRecordValue {

        #region Fields

        private HyperLink lnkToAdd;
        private Panel pnlWrapper;
        private Literal ltlControlContent;
        private IEnumerable<GroupRecordSelect> referencingRecords;
        private IGroup relatedGroup;

        #endregion

        #region Properties

        public override bool DisplayInline {
            get { return false; }
        }

        #endregion

        #region Methods

        protected override void CreateChildControls() {
            base.CreateChildControls();

            this.lnkToAdd = new HyperLink();
            this.Controls.Add(this.lnkToAdd);

            this.pnlWrapper = new Panel();
            this.Controls.Add(this.pnlWrapper);

            this.ltlControlContent = new Literal();
            this.pnlWrapper.Controls.Add(this.ltlControlContent);
        }

        private void SetInstance() {
            this.relatedGroup = Factory.Instance().GetGroup(this.column.RelatedGroupId);
            IEnumerable<GroupRecord> records = new GroupRecords(this.relatedGroup);
            RecordExtension ext = new Extensions(this.relatedGroup).GetGroupRecordExtension();
            if (ext != RecordExtension.NULL)
                records = records.Where(r => ext.ShowOnReferencesRecordsList(r, this.column));
            GroupRecord[] selectedRecords;

            if (this.column.ColumnType == FieldType.ManyReference)
                selectedRecords = this.record.GetRecords(this.column.ColumnName);
            else {
                if (this.record.IsNotNull(this.column.ColumnName)) {
                    GroupRecord refReco = this.record.GetRecord(this.column.ColumnName);
                    if (refReco != null)
                        selectedRecords = new GroupRecord[] { refReco };
                    else
                        selectedRecords = new GroupRecord[0];
                }
                else
                    selectedRecords = new GroupRecord[0];
            }

            int[] selectedRecordsId = selectedRecords.Select(gr => gr.RecordId).ToArray();
            this.referencingRecords = records.Select(gr => new GroupRecordSelect(gr)).ToList();
            foreach (GroupRecordSelect gr in this.referencingRecords) {
                if (selectedRecordsId.Contains(gr.Record.RecordId))
                    gr.Selected = true;
            }
            this.referencingRecords =
                this.ReorderToFloatColumns(4,
                this.referencingRecords.OrderByDescending(grs => grs.Selected).ThenBy(grs => grs.Record.Identyficator).ToArray());
        }

        private List<GroupRecordSelect> ReorderToFloatColumns(int toColumns, GroupRecordSelect[] records) {
            if (records.Length <= toColumns) return records.ToList();
            List<GroupRecordSelect> reordered = new List<GroupRecordSelect>(records.Length);
            Dictionary<int, Queue<GroupRecordSelect>> columns = new Dictionary<int, Queue<GroupRecordSelect>>(toColumns);
            int rows = (int)Math.Ceiling(records.Length / (double)toColumns);
            int fullColumns = toColumns - (rows * toColumns - records.Length);
            int position = 0;
            for (int xc = 0; xc < toColumns; xc++) {
                int take = rows;
                if (xc >= fullColumns) take--;

                Queue<GroupRecordSelect> q = new Queue<GroupRecordSelect>(records.Skip(position).Take(take));
                columns.Add(xc, q);

                position = position + take;
            }
            for (int xr = 1; xr <= rows; xr++) {
                int cr = toColumns;
                if (xr == rows)
                    cr = fullColumns;
                for (int xc = 0; xc < cr; xc++) {
                    reordered.Add(columns[xc].Dequeue());
                }
            }
            return reordered;
        }

        protected override void PopulateControl() {
            this.SetInstance();
            this.EnsureChildControls();
            if (!this.relatedGroup.ReadOnly) {
                this.lnkToAdd.Text = "+ dodaj nowy wpis";
                this.lnkToAdd.Attributes.Add("data-type", "open-popup");
                NemoUrl url = NemoUrl.Get();
                url.View = NemoUrlView.EditRecord;
                url.GroupId = this.column.RelatedGroupId;
                url.RecordId = 0;
                url.AutoClose = true;
                this.lnkToAdd.NavigateUrl = url.GetUrl();
                this.lnkToAdd.CssClass = "edit-references-add";
            }
            else
                this.lnkToAdd.Visible = false;
            this.pnlWrapper.CssClass = "cleanfix edit-references references-" + this.column.ColumnType.ToString().ToLower();
            this.pnlWrapper.ID = "editReferences" + this.column.ColumnName.ToFirstUpperString();

            this.ltlControlContent.Text = this.BuildControlContent();
        }

        private string BuildControlContent() {
            StringBuilder sb = new StringBuilder();
            using (HtmlTextWriter htmlWriter = new HtmlTextWriter(new StringWriter(sb))) {
                foreach (GroupRecordSelect record in this.referencingRecords) {
                    this.BuildRecordContent(htmlWriter, record);
                }
            }
            return sb.ToString();
        }

        private void BuildRecordContent(HtmlTextWriter writer, GroupRecordSelect record) {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "row");
            writer.AddAttribute("data-recordid", record.Record.RecordId.ToString());
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            this.BuildRecordCheckAndName(writer, record);
            this.BuildRecordActions(writer, record.Record);
            writer.RenderEndTag();
        }

        private void BuildRecordCheckAndName(HtmlTextWriter writer, GroupRecordSelect record) {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "recordCheckAndName");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            this.BuildRecordUserSelect(writer, record);
            this.BuildRecordName(writer, record.Record);
            writer.RenderEndTag();
        }

        private void BuildRecordUserSelect(HtmlTextWriter writer, GroupRecordSelect record) {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "check");
            writer.RenderBeginTag(HtmlTextWriterTag.Span);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, "reference-" + this.column.ColumnId);
            writer.AddAttribute(HtmlTextWriterAttribute.Type, (this.column.ColumnType == FieldType.ManyReference) ? "checkbox" : "radio");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, record.Record.RecordId.ToString());
            if (record.Selected)
                writer.AddAttribute(HtmlTextWriterAttribute.Checked, "checked");
            writer.RenderBeginTag(HtmlTextWriterTag.Input);
            writer.RenderEndTag();
            writer.RenderEndTag();
        }

        private void BuildRecordName(HtmlTextWriter writer, GroupRecord record) {
            writer.AddAttribute(HtmlTextWriterAttribute.Title, record.Identyficator);
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            writer.Write(record.Identyficator);
            writer.RenderEndTag();
        }

        private void BuildRecordActions(HtmlTextWriter writer, GroupRecord record) {
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "actions");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddAttribute("data-type", "open-popup");
            NemoUrl url = NemoUrl.Get();
            url.View = NemoUrlView.EditRecord;
            url.GroupId = record.BelongsToGroupId;
            url.RecordId = record.RecordId;
            url.AutoClose = true;
            this.BuildRecordActionLink(writer, url.GetUrl(), "Edytuj rekord", "+ edytuj");
            // this.BuildRecordActionLink(writer, "remove-record:" + record.RecordId, "Usuń rekord", "+ usuń");
            writer.RenderEndTag();
        }

        private void BuildRecordActionLink(HtmlTextWriter writer, string link, string title, string text) {
            writer.AddAttribute(HtmlTextWriterAttribute.Href, link);
            writer.AddAttribute(HtmlTextWriterAttribute.Title, title);
            writer.RenderBeginTag(HtmlTextWriterTag.A);
            writer.Write(text);
            writer.RenderEndTag();
        }

        public override void SaveInRecord() {
            List<int> selectedRefs = new List<int>();
            string rSelected = Page.Request["reference-" + this.column.ColumnId];
            if (!String.IsNullOrEmpty(rSelected)) {
                string[] rSelecteds = rSelected.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                for (int xs = 0; xs < rSelecteds.Length; xs++) {
                    int selected;
                    if (Int32.TryParse(rSelecteds[xs], out selected))
                        selectedRefs.Add(selected);
                }
            }

            if (this.column.ColumnType == FieldType.OneReference) {
                if (selectedRefs.Count == 1)
                    this.record.SetRecord(this.column.ColumnName, selectedRefs[0]);
                else
                    this.record.SetRecord(this.column.ColumnName, 0);
            }
            else {
                this.record.SetRecords(this.column.ColumnName, selectedRefs.ToArray());
            }

        }

        public class GroupRecordSelect {

            public GroupRecord Record { get; set; }
            public bool Selected { get; set; }

            public GroupRecordSelect(GroupRecord record) {
                this.Record = record;
            }

        }

        #endregion

    }
}